#ifndef __THREAD_POOL_HPP__
#define __THREAD_POOL_HPP__

#include <iostream>
#include <vector>
#include <queue>
#include "Thread.hpp"
#include "LockGuard.hpp"
#include "Log.hpp"
#include "Task.hpp"

template <class T>
class ThreadPool
{
private:
    static const int g_thread_num = 10;

private:
    pthread_mutex_t *getMutex()
    {
        return &_lock;
    }

    bool isEmpty()
    {
        return _task_queue.empty();
    }

    void Wait()
    {
        pthread_cond_wait(&_cond, &_lock);
    }

    T getTask()
    {
        T task = _task_queue.front();
        _task_queue.pop();
        return task;
    }

    void Signal()
    {
        pthread_cond_signal(&_cond);
    }

private:
    ThreadPool(int num = g_thread_num)
        : _num(num)
    {
        pthread_mutex_init(&_lock, nullptr);
        pthread_cond_init(&_cond, nullptr);
        for (int i = 0; i < _num; i++)
        {
            _threads.push_back(new Thread(i, routinue, this));
        }
    }

    ThreadPool(const ThreadPool<T> &) = delete;
    const ThreadPool<T> &operator=(const ThreadPool<T> &) = delete;

public:
    void start()
    {
        for (auto &iter : _threads)
        {
            iter->create();
        }
    }

    static void *routinue(void *args)
    {
        ThreadData *td = (ThreadData *)args;
        ThreadPool<T> *tp = (ThreadPool<T> *)td->_args;
        while (true)
        {
            T task;
            {
                LockGuard lg(tp->getMutex());
                while (tp->isEmpty())
                {
                    tp->Wait();
                }
                task = tp->getTask();
            }
            task(td->_name);
        }
    }

    static ThreadPool<T> *getThreadPool(int num = g_thread_num)
    {
        if (_thread_ptr == nullptr)
        {
            pthread_mutex_lock(&_thread_mutex);
            if (_thread_ptr == nullptr)
            {
                _thread_ptr=new ThreadPool<T>(num);
            }
        }
        return _thread_ptr;
    }

    void push(const T &in)
    {
        LockGuard lg(getMutex());
        _task_queue.push(in);
        Signal();
    }

    ~ThreadPool()
    {
        for (auto &iter : _threads)
        {
            iter->join();
            delete iter;
        }
        pthread_mutex_destroy(&_lock);
        pthread_cond_destroy(&_cond);
        delete _thread_ptr;
    }

private:
    std::vector<Thread *> _threads; // 线程总数
    int _num;                       // 记录线程数
    std::queue<T> _task_queue;      // 任务队列
    pthread_mutex_t _lock;          // 锁
    pthread_cond_t _cond;           // 条件变量

    static ThreadPool<T> *_thread_ptr;    // 单例指针
    static pthread_mutex_t _thread_mutex; // 单例锁
};
template <class T>
ThreadPool<T> *ThreadPool<T>::_thread_ptr = nullptr;
template <class T>
pthread_mutex_t ThreadPool<T>::_thread_mutex = PTHREAD_MUTEX_INITIALIZER;

#endif